#include "AAAlgo.h"

const double AAAlgo::roN = 0.9;
const double AAAlgo::roIWD = 0.9;

AAAlgo::AAAlgo(int iterMax, Graph *graph)
{
	this->iterMax = iterMax;
	this->graph = graph;
	init();	
}

void AAAlgo::init()
{
	srand(time(0));
	this->iterCount = 0;
	computeLevel0Nodes();
	this->nIWD = level0Nodes.size();
	this->totalBestSolution.quality = INFINIT;
	IWDs.resize(nIWD);
}

void AAAlgo::spread_randomly()
{
	int size = IWDs.size();
	for(int i=0; i<size; ++i)
		delete IWDs[i];
	
	std::vector <int> set;
	for (int i=0; i<nIWD; ++i)
		set.push_back(i);

	int index;
	while(!set.empty())
	{
		index = rand()%set.size();
		std::vector <int>::iterator it = set.begin();
		IWD *aux = new IWD(set[index], graph->n);
		IWDs.push_back(aux);
		std::cout<<set[index]<<"\n";
		set.erase(it + index, it + index + 1);
	}
}



solution AAAlgo::run_one_iteration()
{
	solution iterationBestSolution;
	spread_randomly_fl();
	int g_size = graph->n;
	bool done = false;
	while(!done)
	{
		for(int i=0; i<g_size; ++i)
		{
			//For each IWD, choose next node with highest probability
			double highestProb = 0.0, currentProbability;
			int nextNode = -1 , currentNode = IWDs[i]->visited.back();
			for(int j=0; j<g_size; ++j)
			{

				if(graph->matrix[currentNode*g_size+j].soil != -1 && IWDs[i]->vis[j] != 1)
				{
					currentProbability = computeProbability(j, IWDs[i]);
					if(highestProb < currentProbability)
					{
						highestProb = currentProbability;
						nextNode = j;
					}
				}
			}
			if(nextNode != -1)
			{	
				double deltaSoil = IWDs[i]->moveTo(nextNode, graph->matrix[currentNode*g_size+nextNode].soil, 2.0);
				graph->matrix[currentNode*nIWD+nextNode].soil = (1 - roN)*graph->matrix[currentNode*nIWD+nextNode].soil - roN*deltaSoil;
			}
			else
				done = true;
		}

	}
	//Select which IWD has the best solution
	double minSoil = IWDs[0]->soil;
	int index = 0;
	for(int i=1; i<g_size; ++i)
	{
		if(IWDs[i]->soil<minSoil)
		{
			minSoil = IWDs[i]->soil;
			index = i;
		}
	}
	iterationBestSolution.nodes = IWDs[index]->visited;
	iterationBestSolution.quality = qualityFunction(iterationBestSolution.nodes);

	//Update the path of the iteration best solution
	int currentNode = IWDs[index]->visited.front();
	int nodesInSol = IWDs[index]->visited.size();
	IWDs[index]->visited.pop_front();
	int nextNode = IWDs[index]->visited.front();
	IWDs[index]->visited.pop_front();
	while(!IWDs[index]->visited.empty())
	{
		graph->matrix[currentNode*nIWD+nextNode].soil = (1+roIWD)*graph->matrix[currentNode*nIWD+nextNode].soil
			- roIWD*IWDs[index]->soil/(nodesInSol-1);
	}
	return iterationBestSolution;
}

void AAAlgo::run()
{
	while(iterCount!=iterMax)
	{
		solution ibs = run_one_iteration();
		if(ibs.quality>totalBestSolution.quality)
			totalBestSolution = ibs;
		++iterCount;
	}
}

double AAAlgo::g(double pathSoil, double minResult)
{
	if(minResult>0.0)
		return pathSoil;
	else
		return pathSoil - minResult;
}

double AAAlgo::f(double pathSoil, double minResult)
{
	return 1/(EPSILON + g(pathSoil, minResult));
}


double AAAlgo::min(IWD *iwd)
{
	//min(soil(i, k)), when k not in visited list
	int currentNode = iwd->visited.back();
	double min = graph->matrix[currentNode*nIWD+currentNode].soil;
	for(int k=0; k<nIWD; ++k)
		if(!iwd->vis[k] && graph->matrix[currentNode*nIWD+k].soil != -1)
			if(graph->matrix[currentNode*nIWD+k].soil<min)
				min = graph->matrix[currentNode*nIWD+k].soil;
	return min;
}


double AAAlgo::computeProbability(int j, IWD *iwd)
{
	int currentNode = iwd->visited.back();
	double probability = f(graph->matrix[currentNode*nIWD+j].soil, min(iwd));
	double sum = 0.0;
	for(int k=0; k<nIWD; ++k)
		if(!iwd->vis[k])
			sum += f(graph->matrix[currentNode*nIWD+k].soil, min(iwd));
	probability /= sum;
	return probability;
}


double AAAlgo::qualityFunction(std::list<int> nodes)
{
	double q = 0.0;

	double sum = 0.0;

	std::list<int>::iterator it;

	for(it = nodes.begin(); it != nodes.end(); it++);







	return q;
}

void AAAlgo::spread_randomly_fl()
{
	int size = IWDs.size();
	for(int i=0; i<size; ++i)
		delete IWDs[i];	

	std::vector <int> set;
	for (int i=0; i<nIWD; ++i)
		set.push_back(i);

	int index;
	while(!set.empty())
	{
		index = rand()%set.size();
		std::vector <int>::iterator it = set.begin();
		IWD *aux = new IWD(set[index], graph->n);
		IWDs.push_back(aux);
		std::cout<<set[index]<<"\n";
		set.erase(it + index, it + index + 1);
	}
}

void AAAlgo::computeLevel0Nodes()
{
	std::vector<Service *> nodes = graph->getServiceNodes();
	for(int i=0; i<nodes.size(); ++i)
	{
		if(nodes[i]->level == 1)
			level0Nodes.push_back(i);
	}
}










